#include <string.h>
#include "curl/curl.h"
#include "common.h"
#include "utils.h"
#include <http_manager.h>
#include "ui_task.h"
/* <DESC>
 * Get a single file from an FTP server.
 * </DESC>
 */

static int Downloading = CURL_CANCEL;

void CancelDownloadFile(void)
{
    Downloading = CURL_CANCEL;
}

static size_t my_fwrite(void *buffer, size_t size, size_t nmemb, void *context)
{
    HttpContext *out = (HttpContext *)context;
    // printf("fwrite filename:%s\n", out->filename);
    if (!out->stream)
    {
        /* open file for writing */
        out->stream = fopen(out->filename, "wb");
        if (!out->stream)
            return -1; /* failure, can't open file to write */
    }
    return fwrite(buffer, size, nmemb, out->stream);
}

/* this is how the CURLOPT_XFERINFOFUNCTION callback works */
static int xferinfo(void *context,
                    curl_off_t dltotal, curl_off_t dlnow,
                    curl_off_t ultotal, curl_off_t ulnow)
{
    HttpContext *myp = (HttpContext *)context;
    CURL *curl = myp->curl;
    TIMETYPE curtime = 0;

    curl_off_t transfer_rate = 0;
    curl_off_t estimate_time = 0;

    if(Downloading == CURL_CANCEL){
        printf("cancel downloding ....\n");
        return -1;
    }

    curl_easy_getinfo(curl, TIMEOPT, &curtime);

    /* under certain circumstances it may be desirable for certain functionality
     to only run every N seconds, in order to do this the transaction time can
     be used */
    if ((curtime - myp->lastruntime) >= MINIMAL_PROGRESS_FUNCTIONALITY_INTERVAL)
    {
        myp->lastruntime = curtime;
        myp->progress = dlnow * 100.0 / dltotal;

        transfer_rate = dlnow - myp->lastdlsize;
        myp->lastdlsize = dlnow;
        FormatRate(myp->transfer_rate_str, transfer_rate);

        estimate_time = transfer_rate == 0 ? 0 : (dltotal - dlnow) / transfer_rate;
        //把秒数转换成00:00:00格式
        FormatTime(myp->estimate_time_str, estimate_time);

        fprintf(stderr, "Progress: %.1f%% transfer_rate:%s, estimate:%s\r\n", 
            myp->progress, myp->transfer_rate_str,myp->estimate_time_str);
        fprintf(stderr, "DOWN: %" CURL_FORMAT_CURL_OFF_T " of %" CURL_FORMAT_CURL_OFF_T "\r\n",
                dlnow, dltotal);

        updateProcess(myp);
    }


    return 0;
}

static int getUrlFileName(char *filename, const char *url)
{
    char temp_url[FILENAME_LEN] = {0};

    if (url == NULL || url[0] == 0)
    {
        printf("getUrlFileName url para error\n");
        return RETURN_FAILED;
    }

    strcpy(temp_url, url);
    char *p = temp_url;

    int url_len = strlen(temp_url);
    //123456 '\0'
    p += url_len;
    int count = 0;
    while (*p != '/' && count != url_len)
    {
        p--;
        count++;
    }

    if (*p != '/')
    {
        printf("getUrlFileName failed\n");
        return RETURN_FAILED;
    }

    strcpy(filename, p + 1);
    p = filename;
    while (*p != '\0')
    {
        if (*p == '?' || *p == '#')
        {
            *p = '\0';
            break;
        }
        p++;
    }

    printf("filename :%s\n", filename);
    return RETURN_OK;
}

static size_t header_callback(char *buffer, size_t size,
                              size_t nitems, void *context)
{
    /* received header is nitems * size long in 'buffer' NOT ZERO TERMINATED */
    /* 'userdata' is set with CURLOPT_HEADERDATA */
    HttpContext *httpContext = (HttpContext *)context;

    printf("size:%ld, buffer:%s\n", nitems * size, buffer);

    //Content-Length: 6379

    return nitems * size;
}

void *RequestUrl(void *vargp)
{
    CURL *curl;
    CURLcode res;
    HttpContext *context = (HttpContext *)vargp;
    Downloading = CURL_DOWNLOADING;

    //获取文件名
    getUrlFileName(context->filename, context->url);
    curl_global_init(CURL_GLOBAL_DEFAULT);

    curl = curl_easy_init();
    if (curl)
    {
        /*
     * You better replace the URL with one that works!
     */
        context->curl = curl;
        //设置下载URL
        curl_easy_setopt(curl, CURLOPT_URL, context->url);
        //打开重定向
        curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);

        //只请求HEADER
        curl_easy_setopt(curl, CURLOPT_NOBODY, context->headonly);

        curl_easy_setopt(curl, CURLOPT_MAX_RECV_SPEED_LARGE, (curl_off_t)100000);
        //设置HEADER回调
        curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, header_callback);
        curl_easy_setopt(curl, CURLOPT_HEADERDATA, context);

        /* Define our callback to get called when there's data to be written */
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, my_fwrite);
        /* Set a pointer to our struct to pass to the callback */
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, context);

        /* enable progress meter */
        curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L);
        curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, xferinfo);
        /* pass the struct pointer into the xferinfo function, note that this is
         an alias to CURLOPT_PROGRESSDATA */
        curl_easy_setopt(curl, CURLOPT_XFERINFODATA, context);
        /* Switch on full protocol/debug output */
        //curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);

        res = curl_easy_perform(curl);

        curl_easy_getinfo(curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD_T, &context->totalsize);
        curl_easy_getinfo(curl, CURLINFO_HTTP_CODE, &context->http_code);
        
        
        /* always cleanup */
        curl_easy_cleanup(curl);

        context->curl_code = res;
        if (CURLE_OK != res)
        {
            /* we failed */
            fprintf(stderr, "curl told us %d\n", res);
        }
    }

    if (context->stream)
    {
        fclose(context->stream); /* close the local file */
        context->stream = NULL;
        free(context);
    }


    curl_global_cleanup();

    return 0;
}